<?php

namespace System\Configure;

use ArrayAccess;

/**
 * 配置抽象类
 *
 * @package Dream
 * @subpackage Config
 * @namespace System\Configure
 * @author lewis (lewisld@yeah.net)
 */
abstract class AbstractConfig implements ArrayAccess, ConfigInterface
{
    /**
     * 配置数据列表
     *
     * @access protected
     * @var array
     */
    protected $data = [];

    /**
     * 缓存的配置数据列表
     *
     * @access protected
     * @var array
     */
    protected $cache = [];

    /**
     * 所有加载的配置文件列表
     *
     * @access protected
     * @var array
     */
    protected $fileList = [];

    /**
     * 构造函数方法，并设置默认选项
     *
     * @access public
     * @param array $data 配置数据
     */
    public function __construct($data)
    {
        $data = $data ? $data : $this->$data;
        $this->data = array_merge($this->getDefault(), $data);
        unset($data);
    }

    /**
     * 默认的配置数组
     *
     * @access protected
     * @return array 返回会默认的配置数组
     */
    protected function getDefault()
    {
        return array();
    }

    /**
     * 获取配置项值
     *
     * @access public
     * @param string $key 配置项键名，多个键名之间以“.”分隔
     * @param mixed $default 默认值，当配置项不存在或为空时有效
     * @return mixed 返回配置项值
     */
    public function get($key, $default = null)
    {
        // 检查是否已经缓存，如果已经缓存则从缓存中获取数据
        if (isset($this->cache[$key])) {
            return $this->cache[$key];
        }
        $root = &$this->data;
        foreach (explode('.', $key) as $part) {
            if (!isset($root[$part])) {
                return $default; // 配置项不存在返回默认值
            }
            $root = &$root[$part];
        }
        return $root;
    }

    /**
     * 设置配置项
     *
     * @access public
     * @param string $key 配置项键名，多个键名之间以“.”分隔
     * @param mixed $value 配置项值
     * @return void 没有返回值
     */
    public function set($key, $value)
    {
        $root = &$this->data;
        foreach (explode('.', $key) as $part) {
            if (!isset($root[$part])) {
                $root[$part] = [];
            }
            $root = &$root[$part];
        }
        $this->cache[$key] = $root = $value;
        unset($root, $part);
   }

    /**
     * 检索配置项是否存在
     *
     * @access public
     * @param string $key 配置项键名
     * @return bool 如果配置项存在就返回“true”，否则返回“false”
     */
    public function exist($key)
    {
        // 检查是否已经缓存，如果已经缓存则从缓存中获取数据
        if (isset($this->cache[$key])) {
            return true;
        }
        $root = &$this->data;
        foreach (explode('.', $key) as $part) {
            if (isset($root[$part])) {
                return true; // 配置项存在
            }
            $root = &$root[$part];
        }
        return false;
    }

    /**
     * 获取所有配置项
     *
     * @access public
     * @return array 返回所有配置项
     */
    public function getAllConfig()
    {
        return $this->data;
    }

    /**
     * 获取所有以缓存的配置项
     *
     * @access public
     * @return array 返回所所有以缓存的配置项
     */
    public function getAllCacheConfig()
    {
        return $this->cache;
    }

    /**
     * 获取一个偏移位置的值
     *
     * @access public
     * @param  string $offset 偏移位置
     * @return mixed 返回配置项值
     */
    public function offsetGet($offset)
    {
        return $this->get($offset);
    }

    /**
     * 检查一个偏移位置是否存在
     *
     * @access public
     * @param  string $offset 偏移位置
     * @return bool 如果偏移位置存在就返回“true”，否则返回“false”
     */
    public function offsetExists($offset)
    {
        return $this->exist($offset);
    }

    /**
     * 设置一个偏移位置的值
     *
     * @access public
     * @param  string $offset 偏移位置
     * @param  mixed  $value 配置项值
     * @return void 没有返回值
     */
    public function offsetSet($offset, $value)
    {
        $this->set($offset, $value);
    }

    /**
     * 复位一个偏移位置的值
     *
     * @access public
     * @param  string $offset
     * @return void 没有返回值
     */
    public function offsetUnset($offset)
    {
        $this->set($offset, null);
    }
}
